<template>
  <div class="dynamic-component-renderer" >
    <component 
      :is="resolvedComponent"
      v-if="resolvedComponent"
      v-bind="props.componentData"
      :ref="setDynamicRef"
      :key="props.componentData.id"
      :style="componentStyle"
      class="rendered-component"
	  @update:visible="handleVisible"
    />
    <div v-else class="fallback-component">
      <div class="fallback-content">
        <i :class="fallbackIcon" class="fallback-icon"></i>
        <div class="fallback-text">{{ componentData.title || '未知组件' }}</div>
        <div class="fallback-type">{{ componentData.type }}</div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch, markRaw, shallowRef, defineExpose, onUnmounted } from 'vue'
import { componentManager, type ComponentConfig } from './util/DynamicComponentUtil'
import { ComponentInstance } from '@/types/visual-app'
import { ComponentLibraryService } from '@/api/visual/componentLibraryApi'
import { useDynamicComponentStore } from '@/store/dynamicComponent'
const dynamicComponentStore = useDynamicComponentStore();
const emit = defineEmits<{
  (e: 'update:visible', state:boolean): void
}>()
// Props
interface Props {
  componentData: ComponentInstance
  width?: number
  height?: number
}

const props = withDefaults(defineProps<Props>(), {
  width: undefined,
  height: undefined
})


// 响应式数据
const resolvedComponent = shallowRef<any>(null)
const loading = ref(false)
const error = ref<string | null>(null)


const componentStyle = computed(() => {
  return {
    width: props.width ? `${props.width}px` : '100%',
    height: props.height ? `${props.height}px` : '100%'
  }
})

const fallbackIcon = computed(() => {
  const config = componentManager.getComponentConfig(props.componentData.type)
  return config?.icon || 'el-icon-question'
})

// 移除本地 metaCache 和 componentCache

const loadComponent = async () => {
  if (!props.componentData.type) {
    error.value = '组件类型未定义'
    return
  }

  loading.value = true
  error.value = null

  try {
    const cacheKey = props.componentData.componentId;  
    const meta = await componentManager.getComponentMeta(cacheKey, getComponentLById);

    // 处理路径，全部用相对路径 ./ 开头
    let importPath = meta.path || '';
    if (importPath.startsWith('/')) {
      importPath = '..' + importPath; // '/widget/xxx.vue' -> '../widget/xxx.vue'
    } else if (!importPath.startsWith('.')) {
      // 去掉前导 widget/ 或 /widget/
      importPath = '../widget/' + importPath.replace(/^[/\\]?widget[/\\]?/, '');
    }

    const asyncComponent = componentManager.getAsyncComponent(importPath);

    const component: ComponentConfig = {
      id: meta.id,
      type: meta.type || props.componentData.type,
      name: meta.name || '',
      icon: meta.icon || '',
      category: meta.category || '',
      description: meta.description || '',
      defaultWidth: meta.defaultWidth || 400,
      defaultHeight: meta.defaultHeight || 300,
      defaultData: meta.defaultData || {},
      props: meta.props || [],
      component: asyncComponent
    }

    if (component) {
      resolvedComponent.value = markRaw(component.component)
    } else {
      error.value = `无法加载组件: ${props.componentData.type}`
    }
  } catch (err) {
    error.value = `加载组件失败: ${err}`
    console.error('Component loading error:', err)
  } finally {
    loading.value = false
  }
}


const getComponentLById=async ()=>{
  return await ComponentLibraryService.get(props.componentData.componentId);
}

function clearCache() {
  componentManager.clearCache();
}

// 用于父组件缓存所有动态组件实例
const setDynamicRef = (el: any) => {
  if (props.componentData.id) {
    dynamicComponentStore.setRef(props.componentData.id, {
		id:props.componentData.id,
		componentId:props.componentData.componentId,
		props:props.componentData,
		ref: el
	})
  }
}

onUnmounted(() => {
  if (props.componentData.id) {
    dynamicComponentStore.removeRef(props.componentData.id)
  }
})

// 监听组件类型变化
watch(() => props.componentData.type, () => {
  loadComponent()
}, { immediate: true })


const handleVisible=(state:boolean)=>{
	props.componentData.visible=state;
}

// 组件挂载时加载
onMounted(() => {
  //loadComponent()
})

// 暴露方法
defineExpose({
  reload: loadComponent,
  clearCache,
  setDynamicRef,
  // getComponentProps: () => componentProps.value
})
</script>

<style lang="scss" scoped>
.dynamic-component-renderer {
  width: 100%;
  height: 100%;
  position: relative;
  .rendered-component {
    width: 100%;
    height: 100%;
  }
  
  .fallback-component {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f7fa;
    border: 1px dashed #c0c4cc;
    border-radius: 4px;
    
    .fallback-content {
      text-align: center;
      color: #909399;
      
      .fallback-icon {
        font-size: 32px;
        margin-bottom: 8px;
        opacity: 0.6;
      }
      
      .fallback-text {
        font-size: 14px;
        font-weight: 500;
        margin-bottom: 4px;
      }
      
      .fallback-type {
        font-size: 12px;
        opacity: 0.8;
      }
    }
  }
}

// 加载状态
.loading {
  .fallback-component {
    .fallback-content {
      .fallback-icon {
        animation: spin 1s linear infinite;
      }
    }
  }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
</style> 